package br.ugf.projeto.agentes;

import br.ugf.projeto.util.MessageConstants;
import jade.core.Agent;
import jade.core.behaviours.CyclicBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;

import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * </p>
 * 
 * @author Rodrigo Souza
 * @version 1.0 Created on 24/03/2008
 */
/**
 * <p>
 * </p>
 * 
 * @author Rodrigo Souza, Alexandre Zulu, Fabio Girotto
 * @version 1.0 Created on 01/06/2008
 */
public class Fornecedor
	extends Agent
{

	/**
	 * <p>
	 * </p>
	 * 
	 * @author Rodrigo Souza, Alexandre Zulu, Fabio Girotto
	 * @version 1.0 Created on 01/06/2008
	 */
	class ServidorOrdensDeCompra
		extends CyclicBehaviour
	{

		/**
		 * <p>
		 * Field <code>serialVersionUID</code>
		 * </p>
		 */
		private static final long serialVersionUID = 1L;

		/**
		 * <p>
		 * </p>
		 * 
		 * @see jade.core.behaviours.Behaviour#action()
		 */
		@Override
		public void action()
		{
			// Process only ACCEPT_PROPOSAL Message
			final MessageTemplate mt = MessageTemplate.MatchPerformative( ACLMessage.ACCEPT_PROPOSAL );
			final ACLMessage msg = this.myAgent.receive( mt );
			if ( msg != null )
			{
				final String msgType = msg.getContent();
				final ACLMessage reply = msg.createReply();
				if ( msgType.compareTo( "Proposal" ) == 0 )
				{
					reply.setPerformative( ACLMessage.INFORM );
					reply.setContent( MessageConstants.CONTENT_INFORM );
					this.myAgent.send( reply );
					System.out.printf( "%s ENVIA INFORM_OK %s\n", getLocalName(), reply );
				}
			}
			else
			{
				block();
			}
		}
	}

	/**
	 * <p>
	 * </p>
	 * 
	 * @author Rodrigo Souza, Alexandre Zulu, Fabio Girotto
	 * @version 1.0 Created on 01/06/2008
	 */
	class ServidorPropostas
		extends CyclicBehaviour
	{

		/**
		 * <p>
		 * Field <code>serialVersionUID</code>
		 * </p>
		 */
		private static final long serialVersionUID = 1L;

		/**
		 * <p>
		 * </p>
		 * 
		 * @see jade.core.behaviours.Behaviour#action()
		 */
		@Override
		public void action()
		{
			// Process only CFP Message
			final MessageTemplate mt = MessageTemplate.MatchPerformative( ACLMessage.CFP );
			final ACLMessage msg = this.myAgent.receive( mt );
			try
			{
				if ( msg != null )
				{
					System.out.printf( "%s RECEBENDO CFP %s\n", getLocalName(), msg );
					final String msgType = msg.getContent();
					final ACLMessage reply = msg.createReply();
					final String produtoNome = msg.getUserDefinedParameter( MessageConstants.PARAMETER_PRODUTO );
					final Double preco = Fornecedor.this.estoqueValor.get( produtoNome );
					if ( preco != null )
					{
						if ( msgType.compareTo( MessageConstants.CONTENT_PROPOSAL ) == 0 )
						{
							reply.setPerformative( ACLMessage.PROPOSE );
							reply.setContent( String.valueOf( preco ) );
						}
					}
					else
					{
						reply.setPerformative( ACLMessage.REFUSE );
						reply.setContent( MessageConstants.CONTENT_NOT_AVAIABLE );
					}
					this.myAgent.send( reply );
					System.out.printf( "%s ENVIA PROPOSTA %s\n", getLocalName(), reply );
				}
				else
				{
					block();
				}
			}
			catch ( final Exception e )
			{
				e.printStackTrace();
			}
		}
	} // End of inner class OfferRequestsServer

	/**
	 * <p>
	 * Field <code>serialVersionUID</code>
	 * </p>
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * <p>
	 * </p>
	 */
	protected void inicializaFornecedor()
	{
		final String nomeFabricante = getAID().getName();
		final Object[] args = getArguments();
		if ( ( args != null ) && ( args.length > 0 ) )
		{
			final String tipo = ( String ) args[0];
			final double valor = Double.parseDouble( ( String ) args[1] );
			this.estoqueValor.put( tipo, valor );
			System.out
				.println( "--------------------------------------------------------------------------------------------------" );
			System.out
				.printf( "%s - Agente iniciado  Produto: %s | Preço inicial: %.2f\n", nomeFabricante, tipo, valor );
			System.out
				.println( "--------------------------------------------------------------------------------------------------" );
			registraServico( tipo );
		}
		else
		{
			System.out.println( nomeFabricante + " - Agente terminado - erro nos parâmetros" );
			// Make the agent terminate immediately
			doDelete();
		}
	}

	/**
	 * <p>
	 * </p>
	 * 
	 * @param tipo
	 */
	protected void registraServico( final String tipo )
	{
		// Register the service in the yellow pages
		final DFAgentDescription description = new DFAgentDescription();
		description.setName( getAID() );
		final ServiceDescription sd = new ServiceDescription();
		sd.setType( tipo );
		sd.setName( getAID().getLocalName() );
		description.addServices( sd );
		try
		{
			System.out.println( getAID().getLocalName()
				+ " registrando-se no servico DF do JADE como fornecedor de: "
				+ tipo );
			DFService.register( this, description );
		}
		catch ( final FIPAException e )
		{
			System.err.println( getAID().getName() + " FALHOU AO REGISTRAR-SE NO DF" );
			e.printStackTrace();
		}
	}

	/**
	 * <p>
	 * </p>
	 * 
	 * @see jade.core.Agent#setup()
	 */
	@Override
	protected void setup()
	{
		inicializaFornecedor();
		addBehaviour( new ServidorPropostas() );
		addBehaviour( new ServidorOrdensDeCompra() );
	}

	/**
	 * <p>
	 * </p>
	 * 
	 * @see jade.core.Agent#takeDown()
	 */
	@Override
	protected void takeDown()
	{
		try
		{
			DFService.deregister( this );
		}
		catch ( final FIPAException fe )
		{
			fe.printStackTrace();
		}
		finally
		{
			System.err.println( "---------------------------------------" );
			System.err.printf( "Agente %s FINALIZADO\n", getLocalName() );
			System.err.println( "---------------------------------------" );
		}
	}

	/**
	 * <p>
	 * Field <code>estoqueValor</code>
	 * </p>
	 */
	Map<String, Double> estoqueValor = new HashMap<String, Double>();

}
